package com.example.tccdemo.service;

import com.example.tccdemo.db163.dao.AccountAMapper;
import com.example.tccdemo.db163.model.AccountA;
import com.example.tccdemo.db164.dao.AccountBMapper;
import com.example.tccdemo.db164.model.AccountB;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @author caryguan
 * @version V1.0
 * @Package com.example.tccdemo
 * @date 2020/10/15 19:18
 */

@org.springframework.stereotype.Service
public class AccountService {

    @Resource
    private AccountAMapper accountAMapper;
    @Resource
    private AccountBMapper accountBMapper;

    @Transactional(transactionManager = "tm163", rollbackFor = Exception.class)
    public void transferAccount() {
        AccountA accountA = accountAMapper.selectByPrimaryKey(1);

        //给A账户减去200块
        accountA.setBalance(accountA.getBalance().subtract(new BigDecimal(200)));
        accountAMapper.updateByPrimaryKey(accountA);

        //给B加上200块
        AccountB accountB = accountBMapper.selectByPrimaryKey(2);
        accountB.setBalance(accountB.getBalance().add(new BigDecimal(200)));
        accountBMapper.updateByPrimaryKey(accountB);
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            //给B加上200块
            AccountB accountb = accountBMapper.selectByPrimaryKey(2);
            accountb.setBalance(accountb.getBalance().subtract(new BigDecimal(200)));
            accountBMapper.updateByPrimaryKey(accountb);

            //这里还需要抛出,如果不抛出异常的话,那么方法正常结束后,第一个事务管理器就提交事务了,然而B我们是做了补偿的,所以需要抛出异常确保第一个事务也回滚
            throw e;

            //TIPS 这里特别要注意!事务补偿最好不要使用,他需要程序开发人员对业务流程十分熟悉,了解其特别容易出现问题的地方,不推荐使用这种方式做分布式事务的数据一致性
            //而且在补偿的时候也有可能发生异常,需要循环嵌套补偿,相当于递归补偿,可以设置一个最大重试的次数,超过次数,记录下来并且进行人工的介入
        }

    }
}